﻿///////////////////////////////////////////////////////////////////////////////
/// Copyright (c) by longshuang@msn.cn 2014.
/// All rights reserved.
///
/// @File	: Engine.Crypto.hpp
/// @Brief	: 加解密及校验相关接口
/// @Author	: Leo Zhao <longshuang@msn.cn>
/// @Date	: 2014-12-23
///
/// CHANGELOG
///		2014-12-30	增加不重复Hash值计算接口
/// 	2014-12-23	初版提交
///////////////////////////////////////////////////////////////////////////////
#ifndef		__ENGINE_CRYPTO_INCLUDE__
#define		__ENGINE_CRYPTO_INCLUDE__

#include	<cstdint>
#include	<string>

namespace Engine { namespace Crypto {

	struct MD5 {
		unsigned char	pData[16];

		/// @Brief	: 转换成可阅读的、16进制描述的String
		/// @Param	: NONE
		/// @Return	: 返回含有32个字节的16进制表示的MD5
		std::string		ToString();
	};

	/// @Brief	: 计算CRC，32-bit版
	/// @Param	: nCRC		初始CRC值
	/// @Param	: pData		需要计算的数据头地址
	/// @Param	: uSize		数据的长度
	/// @Return	: 返回计算的值
	extern uint32_t		CalcCRC(uint32_t nCRC, const char * pData, size_t uSize);

	/// @Brief	: 生成不重复的Hash编码采用BKDRHash算法
	/// @Param	: pData		需要计算的数据头地址
	/// @Param	: uSize		数据的长度
	/// @Return	: 返回uint32_t存储的不重复Hash编码
	extern uint32_t		CalcHash(const char * pData, size_t uSize);

	/// @Brief	: 计算数据的Md5值
	/// @Param	: pData		需要计算MD5值的数据头地址
	/// @Param	: uSize		数据的长度
	/// @Return	: MD5值
	extern MD5			CalcMD5(const char * pData, size_t uSize);

	/// @Brief	: AES + 随机密码本混合加密方式，速度快，安全性高
	/// @Note	: 该加密为混合加密方式。使用时请注意以下几点：
	///		1. 优先AES加密10轮，128bit;
	///		2. 对不足16Byte(128bit)的数据末尾不再使用AES加密，改用XOR随机密码本加密；
	///		3. 加密需要密码只使用前11 * 16个Byte，小于此值时自动从头循环填充; 
	class Crypter {
	public:
		Crypter(const char * pKeys, size_t uKeySize);
		virtual ~Crypter() {}

		/// @Brief	: 加密接口
		/// @Param	: pData		需要加密的数据头地址
		/// @Param	: uDataSize	数据的长度
		/// @Return	: NONE
		void		Encrypt(char * pData, size_t uDataSize);

		/// @Brief	: 解密接口
		/// @Param	: pData		需要解密的数据头地址
		/// @Param	: uDataSize	数据的长度
		/// @Return	: NONE
		void		Decrypt(char * pData, size_t uDataSize);

	public:
		/// @Brief	: 将指定长度修正为128 * N位的固定长度，方便全部使用AES加密
		/// @Param	: nSize		需要修正的原始长度
		/// @Return	: 返回修正后的长度
		static size_t	FixSize(size_t nSize);

	private:
		void		_AddRoundKey(uint8_t pState[4][4], uint8_t nRound);
		void		_SubBytes(uint8_t pState[4][4]);
		void		_ShiftRows(uint8_t pState[4][4]);
		void		_MixColumns(uint8_t pState[4][4]);

		void		_InvSubBytes(uint8_t pState[4][4]);
		void		_InvShiftRows(uint8_t pState[4][4]);
		void		_InvMixColumns(uint8_t pState[4][4]);

	private:
		uint8_t		_pKey[11][4][4];
	};

}}

#endif//!	__ENGINE_CRYPTO_INCLUDE__
